import pandas as pd
import numpy as np


def make_df(index, columns):
    data = [[str(i) + str(j) for i in columns] for j in index]
    df = pd.DataFrame(data=data, columns=columns)
    return df


df1 = make_df([1, 2, 3, 4], list('ABCD'))
df2 = make_df([3, 4, 5, 6], list('CDEF'))
print(df1)
print(df2)
# 1.使用append函数添加
# 由于在后面级联的使用非常普遍，因此有一个函数append专门用于在后面添加
print("\n1.使用append函数添加")
print(df1._append(df2))
# 2.使用merge函数合并
# 类似以MySql中表和表直接的合并
# merge与concat的区别在于，merge需要依据某一共同的行或列来进行合并
# 使用merge合并时，会自动根据两者相同column名称的那一列，作为key来进行合并
# 每一列元素的顺序不要求一致
print("\n2.使用merge函数合并")
print('\n2.1 一对一合并')
df3 = pd.DataFrame(
    {
        'id': [1, 2, 3],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df4 = pd.DataFrame(
    {
        'id': [2, 3, 4],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df3)
print(df4)
print(df4.merge(df3))
print(pd.merge(df3, df4))
# 多对一合并
print('\n2.2 多对一合并')
df5 = pd.DataFrame(
    {
        'id': [1, 2, 2],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df6 = pd.DataFrame(
    {
        'id': [2, 3, 4],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df3)
print(df4)
print(df5.merge(df6))

# 2.3 多对多合并
print('\n2.3 多对多合并')
df7 = pd.DataFrame(
    {
        'id': [1, 2, 2],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df8 = pd.DataFrame(
    {
        'id': [2, 2, 4],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df7)
print(df8)
print(pd.merge(df7, df8))

# 3.key的规范化
print("\n3.key的规范化")
# -- 使用on=显式指定那一列为key，当两个dataframe有多列相同的情况，可以用on指定
df9 = pd.DataFrame(
    {
        'id': [1, 2, 3],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df10 = pd.DataFrame(
    {
        'id': [2, 3, 4],
        'name': ['张三', '李四', '王五'],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df9)
print(df10)
# 如果有多列名称相同，需要指定一列作为连接的字段
print(pd.merge(df9, df10, on='id'))
print(pd.merge(df9, df10, on='name'))
# 如果没有相同的列名，则需要使用left_on和right_on分别指定2个表中的不同列作为连接的字段
df11 = pd.DataFrame(
    {
        'id': [1, 2, 3],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df12 = pd.DataFrame(
    {
        'id2': [2, 3, 4],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df11)
print(df12)
print(pd.merge(df11, df12, left_on='id', right_on='id2'))

# -- 使用left_on=和right_on=分别指定左右dataframe的key列，当左右两边都不相等时使用
df13 = pd.DataFrame(
    {
        'id': [1, 2, 3],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df14= pd.DataFrame(
    {
        'id2': [2, 3, 4],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df13)
print(df14)
# 可以使用行索引作为连接的字段
print(pd.merge(df13, df14, left_index=True, right_index=True))
print(pd.merge(df13, df14, left_on='id', right_index=True))
# -- 当左右两边都有相同的列名时，可以用left_index=True和right_index=True指定使用index作为key


# 4.内合并与外合并
print("\n4.内合并与外合并")
# -- 内合并：只保留两者都有的key（默认模式）
df15 = pd.DataFrame(
    {
        'id': [1, 2, 3],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df16= pd.DataFrame(
    {
        'id': [2, 3, 4],
        'sex': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df15)
print(df16)
print(pd.merge(df15, df16))    # 默认是内连接 相当于数据库inner join
print(pd.merge(df15, df16, how='inner'))
# --外合并how= ‘outer’：补NaN值，保留所有key
# -- 外合并：指的是两个dataframe的连接是基于不同的列，即两个dataframe的列名不完全相同
print('\n4.2 外合并')
# 外连接：会显示两个表的所有数据
print(pd.merge(df15, df16, how='outer'))
# 左合并，右合并：how = 'left' or 'right'，保留左边或右边的key，不包含另一边的key
print('\n4.3 左合并')
# 左连接：显示左边df1表的所有数据和df2表的公共数据
print(pd.merge(df15, df16, how='left'))
print('\n4.4 右合并')
# 右连接：显示右边df2表的所有数据和df1表的公共数据
print(pd.merge(df15, df16, how='right'))

# 5.列冲突的解决
# 当列冲突时，既有多个列名称相同，需要使用on=来制定哪一个列作为key，配合suffixes指定冲突列名
# 可以使用suffixes=自己指定后缀来解决冲突
print("\n5.列冲突的解决")
df15 = pd.DataFrame(
    {
        'id': [1, 2, 3],
        'name': ['张三', '李四', '王五'],
        'age': [21, 22, 23],
    }
)
df16= pd.DataFrame(
    {
        'id': [2, 3, 4],
        'name': ['男', '女', '女'],
        'height': [170, 160, 180]
    }
)
print(df15)
print(df16)
print(pd.merge(df15, df16, on='id'))
print(pd.merge(df15, df16, on='id', suffixes=('_left', '_right')))  # 改掉默认的_x和_y后缀



"""
merge合并总结：
-- 合并有三种现象：一对一、多对一、多对多
-- 合并默认会找相同的列名进行合并，如果有多个列名相同，用on来指定
-- 如果没有列名相同但数据有相同，可以用left_on和right_on分别指定2个表中的不同列作为连接的字段
-- 如果想和index合并，使用left_index=True和right_index=True
-- 如果有多个列相同，合并之后可以通过suffixes来解决冲突
-- 还可以通过how来控制合并的结果，默认是内合并，还有外合并outer、左合并left、右合并right


"""



